//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include "ChannelData.h"
#include "ChannelMagic.h"
#include <stdlib.h>

ChannelData::ChannelData()
{
    m_dataSize = 0;
    m_channelNumber = 0;
    m_data = NULL;
    m_packageNumber = 0;
}

ChannelData::ChannelData(const ChannelData& data)
{
    m_dataSize = data.m_dataSize;
    m_channelNumber = data.m_channelNumber;
    if (data.m_dataSize <= 0) {
        m_data = NULL;
    }
    else {
        m_data = (char *)malloc(RoundSize(data.m_dataSize));
        if (m_data != NULL) {
            memcpy(m_data, data.m_data, data.m_dataSize);
        }
    }
    m_packageNumber = data.m_packageNumber;
}

ChannelData::ChannelData(unsigned int channelNumber,
    char* data, unsigned int dataSize):
    m_dataSize(dataSize)
{
    m_channelNumber = channelNumber;
    m_data = (char *)malloc(RoundSize(dataSize));
    if (m_data != NULL) {
        memcpy(m_data, data, dataSize);
    }
    m_packageNumber = ChannelPackage::NextPackageNumber(); //?
}

ChannelData::~ChannelData()
{
    if (m_data != NULL) {
        free(m_data);
    }
    m_data = NULL;
    m_dataSize = 0;
}

unsigned int ChannelData::GetPackageSize()
{
    // MagicNumber | InfoHeader | InfoHeader2 | PackageNumber | Data | CRC
    return 4 + 4 + 4 + 4 + RoundSize(m_dataSize) + 4;
}

void ChannelData::WriteBuffer(char* buffer)
{
    ChannelMagic cm((unsigned char) ChannelMagic::TYPE_SEND);
    cm.WriteBuffer(buffer);
    buffer += 4;

    WriteInteger(buffer, (m_dataSize<<16)|(0xffff&m_channelNumber));
    buffer += 4;

    WriteInteger(buffer, (m_dataSize<<16)|(0xffff&m_channelNumber));
    buffer += 4;

    WriteInteger(buffer, m_packageNumber);
    buffer += 4;

    memcpy(buffer, m_data, m_dataSize);
    buffer  += RoundSize(m_dataSize);

    WriteInteger(buffer, CRCCheck(m_data, m_dataSize));
}

int ChannelData::Read(ReadInputStream is)
{
    int info_header = 0;
    int info_header_check = 0;
    int check_sum = 0;
    int ret = 0;

    ret = ReadInteger(is, &info_header);
    if (0 != ret) {
        return CHANNEL_IO_ERROR; // io error
    }

    ret = ReadInteger(is, &info_header_check);
    if (0 != ret) {
        return CHANNEL_IO_ERROR; // io error
    }

    if (info_header_check != info_header) {
        return CHANNEL_HEADER_ERROR;
    }

    m_channelNumber = info_header & 0xffff;
    m_dataSize = info_header >> 16;
    if (m_dataSize > ChannelPackage::MAX_DATA_SIZE) {
        return CHANNEL_HEADER_ERROR;
    }

    ret = ReadInteger(is, (int *)&m_packageNumber);
    if (0 != ret) {
        return CHANNEL_IO_ERROR; // io error
    }

    // Read data block and check CRC
    if (m_data != NULL) {
        free(m_data);
    }
    m_data = (char *)malloc(RoundSize(m_dataSize));
    if (NULL == m_data) {
        return CHANNEL_OUT_OF_MEMORY;
    }

    ret = is(m_data, RoundSize(m_dataSize), NULL);
    if (0 != ret) {
        return CHANNEL_IO_ERROR;
    }

    ret = ReadInteger(is, &check_sum);
    if (0 != ret) {
        return CHANNEL_IO_ERROR;
    }
    if (check_sum != CRCCheck((void *)m_data, m_dataSize)) {
        return CHANNEL_CRC_ERROR;
    }

    return CHANNEL_OK;
}
